/*
 * Copyright (c) 2006-2011, Petr Panteleyev
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.blogclient;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Locale;

import javax.swing.JFrame;

import org.panteleyev.blogapi.APIKeysProvider;
import org.panteleyev.utilities.FileUtil;

final public class Options {
    // Flickr keys
    public static String FLICKR_API_KEY = "";
    public static String FLICKR_API_SECRET = "";

    // Twitter keys
    public static String TWITTER_CONSUMER_KEY = "";
    public static String TWITTER_CONSUMER_SECRET = "";

    private interface OptionsBase {
        String getFileName();
    }

    /* Network Options */
    private static class NetworkOptions implements OptionsBase, Serializable {
        private final static long serialVersionUID = 20100208L;

        String  proxyServer;
        int     proxyPort;
        String  httpsProxyServer = "";
        int     httpsProxyPort;
        String  proxyUserName = "";
        String  proxyPasswd = "";
        boolean proxyEnabled;
        boolean proxyAuth;

        @Override
        public String getFileName() {
            return "network.pb";
        }
    }

    public static String getProxyServer() { return netOpt.proxyServer; }
    public static int getProxyPort() { return netOpt.proxyPort; }
    public static String getHttpsProxyServer() { return netOpt.httpsProxyServer; }
    public static int getHttpsProxyPort() { return netOpt.httpsProxyPort; }
    public static boolean isProxyEnabled() { return netOpt.proxyEnabled; }
    public static boolean getProxyAuth() { return netOpt.proxyAuth; }
    public static String getProxyUser() { return netOpt.proxyUserName; }
    public static String getProxyPasswd() { return netOpt.proxyPasswd; }

    public static void setProxyServer(String addr) { netOpt.proxyServer = addr; }
    public static void setProxyPort(int port) { netOpt.proxyPort = port; }
    public static void setHttpsProxyServer(String addr) { netOpt.httpsProxyServer = addr; }
    public static void setHttpsProxyPort(int port) { netOpt.httpsProxyPort = port; }
    public static void setProxyUser(String name) { netOpt.proxyUserName = name; }
    public static void setProxyPasswd(String passwd) { netOpt.proxyPasswd = passwd; }
    public static void setProxyEnabled(boolean enabled) { netOpt.proxyEnabled = enabled; }
    public static void setProxyAuth(boolean auth) { netOpt.proxyAuth = auth; }

    /* Font Options */
    private static class FontOptions implements OptionsBase, Serializable {
        private final static long serialVersionUID = 20100208L;

        String  editorFontName;
        int     editorFontStyle;
        int     editorFontSize;

        String  ljAdminConsoleFontName;
        int     ljAdminConsoleFontStyle;
        int     ljAdminConsoleFontSize;

        @Override
        public String getFileName() {
            return "fonts.pb";
        }
    }

    public static void setEditorFont(String name, int style, int size) {
        fontOpt.editorFontName = name;
        fontOpt.editorFontStyle = style;
        fontOpt.editorFontSize = size;
    }

    public static void setLJAdminConsoleFont(String name, int style, int size) {
        fontOpt.ljAdminConsoleFontName = name;
        fontOpt.ljAdminConsoleFontStyle = style;
        fontOpt.ljAdminConsoleFontSize = size;
    }

    /* Applications Options */
    private static class ApplicationOptions implements OptionsBase, Serializable {
        private final static long serialVersionUID = 20100208L;

        boolean showToolbars;
        boolean showProfileManager = true;
        String  externalBrowserCommand = "";
        int     localeIndex;
        boolean useExternalPreview;

        /* Misc */
        boolean makeLinkBold = true;
        boolean makeLinkItalic;

        @Override
        public String getFileName() {
            return "application.pb";
        }
    }

    public static boolean getShowToolbars() { return appOpt.showToolbars; }
    public static boolean getShowProfileManager() { return appOpt.showProfileManager; }
    public static String  getExternalBrowserCommand() { return appOpt.externalBrowserCommand; }
    public static boolean getUseExternalPreview() { return appOpt.useExternalPreview; }
    public static boolean getMakeLinkBold() { return appOpt.makeLinkBold; }
    public static boolean getMakeLinkItalic() { return appOpt.makeLinkItalic; }

    public static void setShowToolbars(boolean b) { appOpt.showToolbars = b; }
    public static void setShowProfileManager(boolean show) { appOpt.showProfileManager = show; }
    public static void setExternalBrowserCommand(String cmd) { appOpt.externalBrowserCommand = cmd; }
    public static void setUseExternalPreview(boolean use) { appOpt.useExternalPreview = use; }
    public static void setMakeLinkBold(boolean b) { appOpt.makeLinkBold = b; }
    public static void setMakeLinkItalic(boolean b) { appOpt.makeLinkItalic = b; }

    /* Bounds */
    private static class Bounds implements OptionsBase, Serializable {
        private final static long serialVersionUID = 20100208L;

        private HashMap<String,Integer> bounds = new HashMap<>();

        @Override
        public String getFileName() {
            return "bounds.pb";
        }

        void put(String key, Integer value) { bounds.put(key, value); }
        Integer get(String key) { return bounds.get(key); }
    }

    private static NetworkOptions       netOpt = null;
    private static FontOptions          fontOpt = null;
    private static ApplicationOptions   appOpt = null;
    private static Bounds               bounds = null;

    /* File names */
    private static final String USER_DIRECTORY  = ".petrus-blogger";
    private static final String PROFILES_FILE   = "profiles.pb";
    private static final String TEMPLATES_FILE  = "templates.pb";

    private static File homeDir;

    private static String[] langs = {"", "en", "ru"};

    public static void setSystemProxySettings() {
        if (isProxyEnabled()) {
            System.setProperty("http.proxyHost", getProxyServer());
            System.setProperty("http.proxyPort", Integer.toString(getProxyPort()));
            System.setProperty("https.proxyHost", getHttpsProxyServer());
            System.setProperty("https.proxyPort", Integer.toString(getHttpsProxyPort()));
            if (getProxyAuth()) {
                System.setProperty("http.proxyUserName", getProxyUser());
                System.setProperty("http.proxyPassword", getProxyPasswd());
                System.setProperty("https.proxyUserName", getProxyUser());
                System.setProperty("https.proxyPassword", getProxyPasswd());
            } else {
                System.clearProperty("http.proxyUserName");
                System.clearProperty("http.proxyPassword");
                System.clearProperty("https.proxyUserName");
                System.clearProperty("https.proxyPassword");
            }
        } else {
            System.clearProperty("http.proxyHost");
            System.clearProperty("https.proxyHost");
        }
    }

    public static void setLocale() {
        if ((getLocaleIndex() > 0) && (getLocaleIndex() < langs.length)) {
            Locale.setDefault(new Locale(langs[getLocaleIndex()]));
        }
    }

    public static int getLocaleIndex() {
        return appOpt.localeIndex;
    }

    public static void setLocaleIndex(int index) {
        appOpt.localeIndex = index;
    }

    public static void saveBounds(java.awt.Component w) {
        String name = w.getClass().getName();

        if (w instanceof JFrame) {
            int state = ((JFrame)w).getExtendedState();
            int max = ((state & java.awt.Frame.MAXIMIZED_BOTH) != 0)? 1 : 0;
            bounds.put(name + "_max", max);
        }

        bounds.put(name + "_x", w.getX());
        bounds.put(name + "_y", w.getY());
        bounds.put(name + "_w", w.getWidth());
        bounds.put(name + "_h", w.getHeight());
    }

    public static void getBounds(java.awt.Component win) {
        String name = win.getClass().getName();
        Integer value;
        int x = ((value = bounds.get(name + "_x")) == null)? 10 : value;
        int y = ((value = bounds.get(name + "_y")) == null)? 10 : value;
        int w = ((value = bounds.get(name + "_w")) == null)? 700 : value;
        int h = ((value = bounds.get(name + "_h")) == null)? 480 : value;

        win.setBounds(x, y, w, h);

        if (win instanceof JFrame) {
            value = bounds.get(name + "_max");
            if (value != null && value == 1) {
                JFrame f = (JFrame)win;
                f.setExtendedState(f.getExtendedState() | java.awt.Frame.MAXIMIZED_BOTH);
            }
        }
    }

    public static void deleteCachedData(UserProfile<?> profile) {
        FileUtil.deleteDirectory(profile.getCacheDirectory());
    }

    public static void checkForUserDirectory() {
        StringBuilder b = new StringBuilder(System.getProperty("user.home"));
        b.append(File.separator);
        b.append(USER_DIRECTORY);

        homeDir = new File(b.toString());
        if (!homeDir.exists()) {
            homeDir.mkdir();
        }
    }

    public static File getHomeDir() { return homeDir; }

    static File getProfilesFile() {
        return new File(homeDir, PROFILES_FILE);
    }

    static File getTemplatesFile() {
        return new File(homeDir, TEMPLATES_FILE);
    }

    private static void storeSettings(OptionsBase...  args) {
        for (OptionsBase opt : args) {
            try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(homeDir, opt.getFileName())))) {
                out.writeObject(opt);
            } catch (Exception ex) {
                MainClass.handleException(null, ex);
            }
        }
    }

    public static void storeSettings() {
        storeSettings(netOpt, fontOpt, appOpt, bounds);
    }

    private static OptionsBase loadSettings(OptionsBase opt) {
        File file = new File(getHomeDir(), opt.getFileName());
        if (!file.exists()) {
            return opt;
        } else {
            try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) {
                OptionsBase res = (OptionsBase)in.readObject();
                return res;
            } catch (IOException | ClassNotFoundException ex) {
                MainClass.handleException(null, ex);
                return opt;
            }
        }
    }

    public static void loadSettings() {
        netOpt = (NetworkOptions)loadSettings(netOpt);
        fontOpt = (FontOptions)loadSettings(fontOpt);
        appOpt = (ApplicationOptions)loadSettings(appOpt);
        bounds = (Bounds)loadSettings(bounds);

        FontManager.setEditorFont(
            fontOpt.editorFontName,
            fontOpt.editorFontStyle,
            fontOpt.editorFontSize);

        FontManager.setLJAdminConsoleFont(
            fontOpt.ljAdminConsoleFontName,
            fontOpt.ljAdminConsoleFontStyle,
            fontOpt.ljAdminConsoleFontSize);

        if ((getLocaleIndex() < 0) || (getLocaleIndex() >= langs.length)) {
            setLocaleIndex(0);
        }
    }

    static {
        try {
            Object obj = Class.forName("org.panteleyev.keysapi.KeysProvider").newInstance();
            if (obj != null && obj instanceof APIKeysProvider) {
                FLICKR_API_KEY = ((APIKeysProvider)obj).getKey(APIKeysProvider.FLICKR_API_KEY);
                FLICKR_API_SECRET = ((APIKeysProvider)obj).getKey(APIKeysProvider.FLICKR_API_SECRET);
                TWITTER_CONSUMER_KEY = ((APIKeysProvider)obj).getKey(APIKeysProvider.TWITTER_CONSUMER_KEY);
                TWITTER_CONSUMER_SECRET = ((APIKeysProvider)obj).getKey(APIKeysProvider.TWITTER_CONSUMER_SECRET);
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            // do nothing, we have no keys
        }

        checkForUserDirectory();

        netOpt =  new NetworkOptions();
        fontOpt = new FontOptions();
        appOpt = new ApplicationOptions();
        bounds = new Bounds();
    }
}
